
module LanguageGenerator where
import LanguageDef
import LanguageTransform
import Synchronizers
import qualified Data.Map as Map

headText = "module Main where\n\
\import Synchronizers\n\
\import CommandLine\n\
\import System\n\
\main = do\n\
\    args <- getArgs\n\
\    run __main args\n\
\__main = _main "

generateWithHeader :: String -> Node -> ShowS
generateWithHeader header node = showString header.mainVarList node.(generate' node)


generate :: Node -> ShowS
generate node = generateWithHeader headText node

mainVarList node = foldl (\showS name ->showS.shows name.showString " ") (showString "") (getMainVarList $ getNodeChildren node)
    where
        getMainVarList :: [Node]->[String]
        getMainVarList (node@Node{nodeType=RelationDefNode "main", children=varlist:_}:_) 
            = map node2name (getNodeChildren varlist)
        getMainVarList (_:xs) = getMainVarList xs
        getMainVarList [] = []
        node2name :: Node -> String
        node2name Node{nodeType=HaskellVarNode name} = name
        node2name x = error $ show x
                        


generate' :: Node -> ShowS
generate' node@Node{nodeType=RootNode, children=children}
    = foldl (\showS node->showS.generate' node) (showString "") children

generate' node@Node{nodeType=RelationDefNode name, children=[varlist, cstraint]}
    = showString "\n_".showString name.showString " ".generate' varlist.
        showString " = ".generate' cstraint.showString "\n"
        
generate' node@Node{nodeType=EqualNode, children=[expr1, expr2]}
    = showString "(".generate' expr1.showString " <=> ".generate' expr2.showString ")"
    
generate' node@Node{nodeType=AndNode, children=[cstraint1, cstraint2]}
    = showString "(".generate' cstraint1.showString " <&> ".generate' cstraint2.showString ")"

generate' node@Node{nodeType=OrNode, children=[cstraint1, cstraint2]}
    = showString "(".generate' cstraint1.showString " <|> ".generate' cstraint2.showString ")"
    
generate' node@Node{nodeType=ForAllNode, children=[dvar, vvar, cstraint]}
    = showString "( forall ".generate' dvar.showString " ".generate' vvar.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=ExistsNode, children=[dvar, vvar, cstraint]}
    = showString "( exists ".generate' dvar.showString " ".generate' vvar.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=Exists'Node, children=[dvar, vvar, cstraint]}
    = showString "( exists' ".generate' dvar.showString " ".generate' vvar.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=OneNode, children=[dvar, vvar, cstraint]}
    = showString "( one ".generate' dvar.showString " ".generate' vvar.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=One'Node, children=[kvar, dvar, vvar, cstraint]}
    = showString "( one' ".generate' kvar.showString " ".
        generate' dvar.showString " ".generate' vvar.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=LetNode, children=[var, expr, cstraint]}
    = showString "( letc ".generate' var.showString " ".generate' expr.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=LeteNode, children=[var, expr, cstraint]}
    = showString "( lete ".generate' var.showString " ".generate' expr.
        showString " ".generate' cstraint.showString ")"

generate' node@Node{nodeType=ProtectNode, children=[var, cstraint]}
    = showString "( protect ".generate' var.showString " ".
        generate' cstraint.showString ")"

generate' node@Node{nodeType=TestNode, children=[cstraint]}
    = showString "( test ".generate' cstraint.showString ")"

generate' node@Node{nodeType=NotNode, children=[cstraint]}
    = showString "( notc ".generate' cstraint.showString ")"

generate' node@Node{nodeType=RelationRefNode name, children=vars}
    = showString "( DynCstraint ( _".showString name.showString " ".
        generateVars vars.showString " ) )"

generate' node@Node{nodeType=DictGetNode, children=[dvar, kvar]}
    = showString "( ".generate' dvar.showString " <.> ".generate' kvar.showString ")"

generate' node@Node{nodeType=IsConstNode, children=[Node{nodeType=StringConstNode s}]}
    = showString "( stringConst ".shows s.showString " )"

generate' node@Node{nodeType=IsConstNode, children=[Node{nodeType=IntConstNode i}]}
    = showString "( intConst ".shows i.showString " )"

generate' node@Node{nodeType=IsConstNode, children=[Node{nodeType=NullConstNode}]}
    = showString "( nullConst )"

generate' node@Node{nodeType=IsConstNode, children=[Node{nodeType=TrueConstNode}]}
    = showString "( stringConst \"@true\" )"

generate' node@Node{nodeType=IsConstNode, children=[Node{nodeType=FalseConstNode}]}
    = showString "( stringConst \"@false\" )"
    
generate' node@Node{nodeType=VarNode name, children=[]}
    = shows name

generate' node@Node{nodeType=VarListNode, children=vars}
    = generateVars vars

generate' node@Node{nodeType=ETraceNode msg, children=[Node{nodeType=VarListNode, children=vars}, expr]}
    = showString "( etrace ".shows msg.showString " (Just (".generateVarList vars.showString " )) ".generate' expr.showString " )"   

generate' node@Node{nodeType=ETraceNode msg, children=[Node{nodeType=AllVarNode}, expr]}
    = showString "( etrace ".shows msg.showString " Nothing ".generate' expr.showString " )"   

generate' node@Node{nodeType=CTraceNode msg, children=[Node{nodeType=VarListNode, children=vars}, cstraint]}
    = showString "( ctrace ".shows msg.showString " (Just ( ".generateVarList vars.showString " )) ".generate' cstraint.showString " )"   

generate' node@Node{nodeType=CTraceNode msg, children=[Node{nodeType=AllVarNode}, expr]}
    = showString "( ctrace ".shows msg.showString " Nothing ".generate' expr.showString " )"   

    
generate' node@Node{nodeType=HaskellVarNode name, children=[]}
    = showString name
    
generate' node = error $ "internal error. Unexpected type in generate':" ++ show node
        
generateVars :: [Node] -> ShowS        
generateVars vars = foldl (\showS var -> showS.generate' var.showString " ") 
                        (showString "")  vars

generateVarList :: [Node] -> ShowS        
generateVarList [] = showString "[]"
generateVarList (x:xs) = showString "[ ".generate' x.(foldr (\var showS-> showString ", ".generate' var.showS)  (showString " ]") xs)  
    